import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { Request , Response } from 'express';
import { Observable } from 'rxjs';

interface JwtUserData {
    userId: number;
    username: string;
    exp?:number;
    iat?:number
}

declare module 'express' {
    interface Request {
        user: JwtUserData
    }
}

@Injectable()
export class AuthGuard implements CanActivate {

    @Inject()
    private reflector: Reflector;

    @Inject(JwtService)
    private jwtService: JwtService;

    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
        const request: Request = context.switchToHttp().getRequest();
        const response: Response = context.switchToHttp().getResponse();
        const requireLogin = this.reflector.getAllAndOverride('require-login', [
            context.getClass(),
            context.getHandler()
        ]);

        if (!requireLogin) {
            return true;
        }

        const authorization = request.headers.authorization;

        if (!authorization) {
            throw new UnauthorizedException('用户未登录');
        }

        try {
            const token = authorization.split(' ')[1];
            const data = this.jwtService.verify<JwtUserData>(token);
            request.user = {
                userId: data.userId,
                username: data.username,
            }
            /* 
            单token 无感刷新  临近一天token过期时 会自动返回新的token 
            */
            const {exp} = data // 过期时间
            const nowTime = Math.floor(Date.now() / 1000)
            const refreshTokenTime = exp - nowTime
            if(refreshTokenTime < 60 * 60 *24 ) {
                response.header('token' , this.jwtService.sign({
                    userId:data.userId,
                    username:data.username
                },{
                    expiresIn:'7d'
                }))
            }
            return true;
        } catch (e) {
            throw new UnauthorizedException('token 失效，请重新登录');
        }
    }
}
